package com.guli.gulimall.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.guli.gulimall.product.web.entity.vo.Catalog2Vo;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guli.common.utils.PageUtils;
import com.guli.common.utils.Query;

import com.guli.gulimall.product.dao.CategoryDao;
import com.guli.gulimall.product.entity.CategoryEntity;
import com.guli.gulimall.product.service.CategoryService;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<CategoryEntity> treeList() {
        // 1、查询所有三级分类
        List<CategoryEntity> allList = baseMapper.selectList(null);

        // 2、在allList中获取一级分类
        List<CategoryEntity> l1List = allList.stream().filter(item ->
                item.getParentCid().equals(0L)
        ).map(item -> { //item: 过滤之后的结果(所有一级种类)
            // 需要找二级分类
            //找子元素的方法
            List<CategoryEntity> children = getChildren(allList, item);
            item.setChildren(children);
            return item;
        }).sorted((s1,s2 )-> {
            return (s1.getSort() != null ? s1.getSort() : 0) - (s2.getSort() != null ? s2.getSort() : 0);
        }).collect(Collectors.toList());


        return l1List;
    }

    @Override
    public List<CategoryEntity> find1List() {
        QueryWrapper<CategoryEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("parent_cid",0);
        return baseMapper.selectList(wrapper);
    }

    //查询三级列表
    @Override
    public Map<String , List<Catalog2Vo>> findCatalog() {
        // 1.为了减少数据库的查询次数
        List<CategoryEntity> categoryEntityList = baseMapper.selectList(null);
        // 2.筛选所有的一级分类
        Map<String , List<Catalog2Vo>> map = categoryEntityList.stream().filter(item ->
                item.getParentCid().equals(0L)
        ).map(item -> {
            return item;
        }).collect(Collectors.toMap(k -> {
            return k.getCatId().toString();
        }, v -> {
            // v 所有的一级分类
            List<Catalog2Vo> l2List = categoryEntityList.stream().filter(item ->
                    item.getParentCid().equals(v.getCatId())
            ).map(item -> {
                // item 就是二级分类
                Catalog2Vo catalog2Vo = new Catalog2Vo();
                catalog2Vo.setCatId(item.getCatId());
                catalog2Vo.setName(item.getName());
                catalog2Vo.setParentCid(item.getParentCid());
                // 收集三级分类
                List<Catalog2Vo.Catalog3Vo> l3List = categoryEntityList.stream().filter(item2 ->
                        item2.getParentCid().equals(item.getCatId())
                ).map(l3 -> {
                    Catalog2Vo.Catalog3Vo catalog3Vo = new Catalog2Vo.Catalog3Vo();
                    catalog3Vo.setId(l3.getCatId());
                    catalog3Vo.setName(l3.getName());
                    catalog3Vo.setParentCid(l3.getParentCid());
                    return catalog3Vo;
                }).collect(Collectors.toList());
                // 赋值三级分类
                catalog2Vo.setCatalog3List(l3List);

                return catalog2Vo;
            }).collect(Collectors.toList());

            return l2List;
        }));
        return map;
    }

    // 首页三级列表缓存
    @Override
    public Map<String, List<Catalog2Vo>> findCatalogRedisCache() {
        //先查询缓存
        String catalogList = redisTemplate.opsForValue().get("catalogList06a");
        //缓存用返回
        if (StringUtils.isNotEmpty(catalogList)) {
            System.out.println("缓存命中");
            return JSON.parseObject(catalogList, new TypeReference<Map<String, List<Catalog2Vo>>>() {});
        } else {
            String uuid = UUID.randomUUID().toString().replace("-", "");
            // 占坑 加上过期时间 防止死锁 过期时间和加锁是原子性的
            Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 30, TimeUnit.SECONDS);
            if (BooleanUtils.isTrue(lock)) {
                //占坑成功
                try {
                    System.out.println("查询数据库");
                    // 缓存没有 去数据库查
                    Map<String, List<Catalog2Vo>> catalog = findCatalog();
                    //查完放入缓存
                    redisTemplate.opsForValue().set("catalogList06a",JSON.toJSONString(catalog),3,TimeUnit.MINUTES);
                    return catalog;
                } finally {
                    //删除锁 redis + lua脚本
                    // 对比删除原子性
                    String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                            "then\n" +
                            "    return redis.call(\"del\",KEYS[1])\n" +
                            "else\n" +
                            "    return 0\n" +
                            "end";
                    redisTemplate.execute(new DefaultRedisScript<Long>(script,Long.class), Collections.singletonList("lock"),uuid);
                }
            } else {
                // 占坑失败
                // 自旋等待 100ms 调用方法本身
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return findCatalogRedisCache();
            }
        }
    }

    private List<CategoryEntity> getChildren(List<CategoryEntity> allList, CategoryEntity categoryEntity) {

        List<CategoryEntity> children = allList.stream().filter(item ->
            item.getParentCid().equals(categoryEntity.getCatId())
        ).map(item -> {
            //查询三级分类
            item.setChildren(getChildren(allList, item));
            return item;
        }).sorted((s1,s2 )-> {
            return (s1.getSort() != null ? s1.getSort() : 0) - (s2.getSort() != null ? s2.getSort() : 0);
        }).collect(Collectors.toList());

        return children;
    }
}